/*!  \file  ThreadPool.cpp
 *	  \brief  
 * 
 *   \details   details
 *   \author    Yordan Madzhunkov German Research School for Simulation Sciences GmbH
 *   \version   1.0
 *   \date      07/14/2013 09:37:09 AM
 *   \copyright GNU Public License.
 */
#include <pthread.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include "macros.h"
#include "ThreadPool.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
#define handle_error_en(en, msg) \
    do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
ThreadPool::ThreadPool(const int MaxNumThreads) {
	maxThreads = MaxNumThreads > 0 ? MaxNumThreads : 1;
	threadIDs = new pthread_t[maxThreads];
	memset(threadIDs, 0, maxThreads * sizeof(pthread_t));
	nThreads = 1; 
	threadIDs[0] = pthread_self();
}

void ThreadPool::joinAll(void ** retVals) {
	if (pthread_equal(pthread_self(),  threadIDs[0])) {
		for (int i = 1; i < maxThreads; i++) if (threadIDs[i]) {
			void * exitPtr = NULL;
			#ifndef NDEBUG
			int info = 
			#endif
			pthread_join(threadIDs[i], &exitPtr);	
			if (retVals) retVals[i] = exitPtr;

			assert(info == 0);
			threadIDs[i] = 0;		
		}
	} else {
		void * exitPtr = NULL;
		pthread_exit(exitPtr);
	}
}
void ThreadPool::execute(const ThreadFunction func,  const int nThreads_,
		 WorkerInfo * args, void ** retVals) {
	nThreads = nThreads_ == -1 ? getOnlineCores() : nThreads_;
	nThreads = nThreads <= maxThreads ? nThreads : maxThreads;
	if (pthread_equal(pthread_self(),  threadIDs[0])) {
		for (int i = 1; i < nThreads; i++) {
			if (threadIDs[i] == 0) {
				void * arg = &args[i];
				int info = pthread_create(&threadIDs[i], NULL, func, arg);
				if (info != 0 ) {
            	handle_error_en(info, "pthread_create");
				} 
			}
		}
	} else {
		MISSING;
	}
	void * arg = &args[0];
	void * res = func(arg);
	if (retVals) retVals[0] = res;
	joinAll(retVals);
}
ThreadPool::~ThreadPool() {
	if (threadIDs) delete [] threadIDs; threadIDs = 0;
}
int ThreadPool::getOnlineCores() { return sysconf( _SC_NPROCESSORS_ONLN ); };

